const Proxy = require('../../proxy')
const webDataUtil = require('../../util/webDataUtil')
const reqlib = require('app-root-path').require
const btbAs = reqlib('/app/common/btb')
const numberUtil = reqlib('/app/util/numberUtil')
const quantityUtilHY = reqlib('/app/common/btb/quantityUtilHY')
const BuySellPolicy = reqlib('/app/common/btb/hy/BuySellPolicy')
const analyzeOverAllUtil = reqlib('/app/common/btb/analyzeOverAll')
const executeRecordService = require('../executeRecord')
const appConfig = reqlib('/config/index')
const commonDataCreate = require('./utils/commonDataCreate')

const BtbIndex = Proxy.BtbIndex
const Dictionary = Proxy.Dictionary

const exBuyHY = reqlib('/app/common/btb/exBuyHY')
const exSellHY = reqlib('/app/common/btb/exSellHY')

const getSysConfig = async () => {
  // 杠杆
  let btbLeverageRes = await Dictionary.findOne({ key: 'btbLeverage' })
  let btbLeverage = parseInt((btbLeverageRes && btbLeverageRes.value) || 1) || 1
  // 仓位配置
  let btbPositionConfigRes = await Dictionary.findOne({ key: 'btbPositionConfig' })
  let btbPositionConfig = (btbPositionConfigRes && btbPositionConfigRes.value) || 100
  if (btbPositionConfig !== '自动') {
    btbPositionConfig = parseInt(btbPositionConfig) || 100
    btbPositionConfig = btbPositionConfig / 100
  }
  // 策略
  let btbStrategyRes = await Dictionary.findOne({ key: 'btbStrategy' })
  let btbStrategy = parseInt((btbStrategyRes && btbStrategyRes.value) || 1) || 1
  // 操作信息
  let btbOpInfo = await Dictionary.findOne({ key: 'btbOpInfo' })
  let btbOpInfoJson = {}
  if (btbOpInfo && btbOpInfo.value) {
    try {
      btbOpInfoJson = JSON.parse(btbOpInfo.value)
    } catch (err) {
      btbOpInfoJson = {}
    }
  } else {
    btbOpInfoJson = {}
  }
  return {
    btbLeverage,
    btbPositionConfig,
    btbStrategy,
    btbOpInfoJson
  }
}

const getBtbIndexConfig = async () => {
  // 找出币
  let btbRes = await BtbIndex.find({
    status: 1,
    hy_status: 1
  }, {
    sort: '-proportion'
  })
  // btbRes = btbRes.filter((v)=>{
  //   return ['GMT'].indexOf(v.code) !== -1
  // })
  // 总占比
  const btbIndexConfig = {
    proportionAll: 0,
    balance: {},
    btbList: []
  }
  // 查K线
  const queryKlineList = []
  for (let i = 0; i < btbRes.length; i++) {
    const btbItem = btbRes[i]
    if (btbItem.proportion) {
      queryKlineList[i] = webDataUtil.getBIBTKlines({
        name: `${btbItem.code}`,
        interval: '15m',
        count: 190 + 20
      })
    }
  }
  const queryKlineListResult = await Promise.all(queryKlineList)
  for (let i = 0; i < btbRes.length; i++) {
    const btbItem = btbRes[i]
    try {
      if (btbItem.proportion) {
        btbIndexConfig.proportionAll += 1
        // K线
        const klineRes = queryKlineListResult[i]
        const asInfo = await btbAs.getItemInfoList(klineRes)
        // 近的在右
        let asList = [...asInfo]
        // 近的在左
        asInfo.reverse()
        const asToday = asInfo[0] || {}
        let allWave = 0
        klineRes.forEach((v) => {
          let wave = numberUtil.countDifferenceRate(v.high, v.low)
          allWave += Math.abs(wave)
        })
        const macdUpRate = btbAs.macdUpVal(asList)
        asInfo.forEach((v, index) => {
          commonDataCreate.asInfoExtend(asInfo, v, index)
        })
        const result = {
          ...commonDataCreate.btbListItemExtend(btbItem, asInfo, asList),
          status: 1,
          hy_status: btbItem.hy_status,
          hourEma510: btbItem.hourEma510 || 0,
          hourEmaInfo: btbItem.hourEmaInfo ? btbItem.hourEmaInfo : {},
          dayEmaInfo: btbItem.dayEmaInfo ? btbItem.dayEmaInfo : {},
          hour4EmaInfo: btbItem.hour4EmaInfo ? btbItem.hour4EmaInfo : {},
          monthEmaInfo: btbItem.monthEmaInfo ? btbItem.monthEmaInfo : {},
          weekEmaInfo: btbItem.weekEmaInfo ? btbItem.weekEmaInfo : {},
          strategy: btbItem.strategy,
          // 取合约的信息
          close: asToday.close,
          asList: asList,
          avWave: allWave / klineRes.length,
          macdUpHigh: macdUpRate > (20 * allWave / klineRes.length),
          macdKeepDays: btbAs.macdKeepDays(asList),
          // 近的在右边
          emInfoList: asList.map((em) => {
            return commonDataCreate.emInfoListItemExtend(em)
          })
        }
        result.minute15EmaInfo = {
          ...commonDataCreate.indexUpdateItemExtend(result, asInfo[0])
        }
        btbIndexConfig.btbList.push(result)
      }
    } catch (err) {
      console.error(`15分钟分析报错[${btbItem.code}]：${err.toString()}`)
    }
  }
  return btbIndexConfig
}

// 填充合约持仓
const fillFuturesAccount = async (config) => {
  const btbIndexConfig = config.btbIndexConfig
  // 资产
  const balanceRes = await webDataUtil.binance('getFuturesAccount')
  const myBalance = balanceRes.data || {}
  const positionsList = myBalance.positions || []
  btbIndexConfig.btbList.forEach((v, index) => {
    const astItem = btbAs.getAstItem(positionsList, v.code)
    const available = parseFloat(astItem.positionAmt)
    const notional = parseFloat(astItem.notional)
    const unrealizedProfit = parseFloat(astItem.unrealizedProfit)
    let notionalAb = Math.abs(notional)
    if (notionalAb < 1) {
      notionalAb = 1
    }
    btbIndexConfig.btbList[index] = {
      ...v,
      // 份额，多单是正，空单是负数
      balance: available,
      // 市值，多单是正，空单是负数
      usdt: notional,
      // 保证金，正数
      initialMargin: parseFloat(astItem.initialMargin),
      // 杠杆
      leverage: parseFloat(astItem.leverage),
      // 持仓涨跌幅，收益/市值，不带杠杆的
      // 如果除initialMargin，那就是带杠杆的收益率
      incomeRate: numberUtil.countRate(unrealizedProfit, notionalAb),
      unrealizedProfit: unrealizedProfit
    }
    btbIndexConfig.balance[v.code] = available
  })
  // 可用
  btbIndexConfig.balance['USDT'] = parseFloat(myBalance.availableBalance)
  // 总资产，不要带上利润，利润投入一般就鱼尾了
  btbIndexConfig.balance['ALL'] = parseFloat(myBalance.totalWalletBalance)
}

// 如果发生了修改的动作，重新查询份额
const reFillFuturesAccount = async (config) => {
  const btbIndexConfig = config.btbIndexConfig
  // 如果发生了修改的动作，重新查询份额
  const br = await webDataUtil.binance('getFuturesAccount')
  const mb = br.data || {}
  // 可用
  btbIndexConfig.balance['USDT'] = parseFloat(mb.availableBalance)
  // 总资产，不要带上利润，利润投入一般就鱼尾了
  btbIndexConfig.balance['ALL'] = parseFloat(mb.totalWalletBalance)
}

const sortBtbIndexList = async (config) => {
  const btbIndexConfig = config.btbIndexConfig
  // 平仓的放前面，这样可以腾挪出资金
  btbIndexConfig.btbList.sort((btbItema, btbItemb) => {
    const a = btbItema.asRes
    const b = btbItemb.asRes
    const pinga = (a.pingKong || a.pingDuo) && !(a.buy || a.sell)
    const pingb = (b.pingKong || b.pingDuo) && !(b.buy || b.sell)
    if (pinga) {
      return -1
    }
    if (pingb) {
      return 1
    }
    return 1
  })
}

// 设置止盈止损订单
const setStopOrder = async (config) => {
  const btbIndexConfig = config.btbIndexConfig
  const btbLeverage = config.btbLeverage
  const btbIndexTotalInfo = config.btbIndexTotalInfo
  for (let i = 0; i < btbIndexConfig.btbList.length; i++) {
    const btbItem = btbIndexConfig.btbList[i]
    await webDataUtil.binance('futuresCancelAll', {
      key: `${btbItem.code}USDT`
    })
    if (btbItem.balance && btbItem.balance < 0) {
      // 空单止盈，止损
      const val = quantityUtilHY.getQuantity({
        pingKong: true
      }, btbItem, btbIndexConfig, btbLeverage)
      if (val) {
        // -20%止盈
        let rate = 0.9
        if (btbIndexTotalInfo.dayAverageScore >= 90) {
          rate = 0.8
        } else if (btbIndexTotalInfo.dayAverageScore >= 70) {
          rate = 0.85
        }
        const stopPrice = quantityUtilHY.formatPrice(btbItem.close * rate, btbItem)
        await webDataUtil.binance('futuresBuy', {
          key: `${btbItem.code}USDT`,
          quantity: val,
          price: stopPrice
        })
      }
    } else if (btbItem.balance && btbItem.balance > 0) {
      // 多单止盈，止损
      const val = quantityUtilHY.getQuantity({
        pingDuo: true
      }, btbItem, btbIndexConfig, btbLeverage)
      if (val) {
        // -20%止盈
        let rate = 1.1
        if (btbIndexTotalInfo.dayAverageScore <= -90) {
          rate = 1.2
        } else if (btbIndexTotalInfo.dayAverageScore <= -70) {
          rate = 1.15
        }
        const stopPrice = quantityUtilHY.formatPrice(btbItem.close * rate, btbItem)
        await webDataUtil.binance('futuresSell', {
          key: `${btbItem.code}USDT`,
          quantity: val,
          price: stopPrice
        })
      }
    }
  }
}

const updateBtbIndexModel = async (config) => {
  const btbIndexConfig = config.btbIndexConfig
  const btbIndexTotalInfo = config.btbIndexTotalInfo
  for (let i = 0; i < btbIndexConfig.btbList.length; i++) {
    const btbItem = btbIndexConfig.btbList[i]
    const asRes = btbItem.asRes
    const em = btbItem.asInfo[0] || {}
    const updateDate = {
      condition_buy_number: btbItem.proportion,
      minute15EmaInfo: {
        ...commonDataCreate.indexUpdateItemExtend(btbItem, em)
      },
      countResultInfo: {
        proportion: btbItem.proportion,
        sell: asRes.sell,
        buy: asRes.buy,
        pingDuo: asRes.pingDuo,
        pingKong: asRes.pingKong,
        buyReason: asRes.buyReason,
        sellReason: asRes.sellReason,
        pingKongReason: asRes.pingKongReason,
        pingDuoReason: asRes.pingDuoReason,
        btbPositionConfig: config.btbPositionConfig,
        positionFen: btbIndexTotalInfo.positionFen
      },
      hy_status: asRes.disabled ? 0 : 1
    }
    await BtbIndex.update({ code: btbItem.code }, updateDate)
  }
}

// 获取合约账户财务信息
module.exports = async function () {
  const btbOpen = await Dictionary.findOne({ key: 'btbOpen' })
  if (!(btbOpen && btbOpen.value === 'true')) {
    return false
  }
  const sysConfig = await getSysConfig()
  // 杠杆
  const btbLeverage = sysConfig.btbLeverage
  // 策略
  const btbStrategy = sysConfig.btbStrategy
  // 操作信息
  const btbOpInfoJson = sysConfig.btbOpInfoJson
  const btbIndexConfig = await getBtbIndexConfig()
  if (btbIndexConfig.btbList.length === 0) {
    return false
  }
  // 填充合约持仓
  await fillFuturesAccount({
    btbIndexConfig
  })
  analyzeOverAllUtil.countItemInfo(btbIndexConfig.btbList)
  const btbIndexTotalInfo = analyzeOverAllUtil.countTotalInfo(btbIndexConfig.btbList)
  // 仓位配置
  let btbPositionConfig = sysConfig.btbPositionConfig
  if (btbPositionConfig === '自动') {
    btbPositionConfig = Math.abs(btbIndexTotalInfo.positionFen) / 100
    const minUsdtSum = appConfig.btb.minNotionalLine * btbIndexConfig.btbList.length
    const minPosition = minUsdtSum / btbIndexConfig.balance['ALL']
    if (minPosition > btbPositionConfig) {
      btbPositionConfig = minPosition
    }
    btbPositionConfig = parseFloat(btbPositionConfig.toFixed(4))
  }
  // 分析
  btbIndexConfig.btbList.forEach((btbItem) => {
    const buySellPolicy = new BuySellPolicy({
      btbItem,
      btbOpInfoJson,
      btbIndexTotalInfo,
      opConfig: {
        btbStrategy,
        btbLeverage,
        btbPositionConfig
      },
      sysConfig
    })
    buySellPolicy.getResult()
    const positionSuggest = buySellPolicy.getPositionSuggest()
    btbItem.proportion = positionSuggest.proportion || 1
    btbItem.resultPosition = positionSuggest.resultPosition
    btbItem.asRes = buySellPolicy
  })
  // 平仓的放前面，这样可以腾挪出资金
  await sortBtbIndexList({
    btbIndexConfig
  })
  // 执行买入卖出
  for (let i = 0; i < btbIndexConfig.btbList.length; i++) {
    const btbItem = btbIndexConfig.btbList[i]
    const asRes = btbItem.asRes
    if (asRes.buy || asRes.sell || asRes.pingDuo || asRes.pingKong) {
      btbIndexConfig.balance['POSITION'] = btbIndexConfig.balance['ALL'] * btbItem.resultPosition
      const val = quantityUtilHY.getQuantity(asRes, btbItem, btbIndexConfig, btbLeverage)
      asRes.val = val
      if (val) {
        const exCommonConfig = {
          usdtKey: `${btbItem.code}USDT`,
          quantity: val,
          btbItem,
          btbLeverage
        }
        const executeRecordCommonConfig = {
          code: btbItem.code,
          leverage: btbLeverage,
          quantity: val,
          btbItem,
          resultPosition: btbItem.resultPosition,
          btbIndexTotalInfo,
          btbPositionConfig
        }
        if (asRes.buy) {
          const exRes = await exBuyHY(exCommonConfig)
          if (exRes) {
            await executeRecordService.addExecuteRecord({
              ...executeRecordCommonConfig,
              type: 'buy',
              reason: asRes.buyReason
            })
          }
        } else if (asRes.sell) {
          const exRes = await exSellHY(exCommonConfig)
          if (exRes) {
            await executeRecordService.addExecuteRecord({
              ...executeRecordCommonConfig,
              type: 'sell',
              reason: asRes.sellReason
            })
          }
        } else if (asRes.pingKong) {
          const exRes = await exBuyHY(exCommonConfig)
          if (exRes) {
            await executeRecordService.addExecuteRecord({
              ...executeRecordCommonConfig,
              type: 'pingKong',
              reason: asRes.pingKongReason
            })
          }
        } else if (asRes.pingDuo) {
          const exRes = await exSellHY(exCommonConfig)
          if (exRes) {
            await executeRecordService.addExecuteRecord({
              ...executeRecordCommonConfig,
              type: 'pingDuo',
              reason: asRes.pingDuoReason
            })
          }
        }
        await reFillFuturesAccount({
          btbIndexConfig
        })
      }
    }
  }
  // 重新填充合约持仓
  await fillFuturesAccount({
    btbIndexConfig
  })
  // 设置止盈
  await setStopOrder({
    btbIndexConfig,
    btbLeverage,
    btbIndexTotalInfo
  })
  // 更新数据库数据
  await Dictionary.update({ key: 'btbOpInfo' }, {
    value: JSON.stringify(btbOpInfoJson)
  })
  await updateBtbIndexModel({
    btbIndexConfig,
    btbPositionConfig,
    btbIndexTotalInfo
  })
  return {
  }
}
